package schema.io;

import java.io.OutputStream;
import java.net.URL;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationEventLocator;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

public abstract class JaxbXmlLoader {
	
	protected abstract String getSchemaPath();

	protected URL xsdPath = JaxbXmlLoader.class.getClassLoader().getResource(getSchemaPath());

	protected abstract String getPackageName();

	public Marshaller getMarshal(Object obj, OutputStream steam) {
		JAXBContext jc;
		Marshaller u = null;
		try {
			jc = JAXBContext.newInstance(getPackageName());
			u = jc.createMarshaller();
			u.marshal(obj, steam);
		} catch (JAXBException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return u;
	}

	public Unmarshaller getUnmarshal() {
		JAXBContext jc;
		Unmarshaller u = null;
		try {
			jc = JAXBContext.newInstance(getPackageName());
			u = jc.createUnmarshaller();
			SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
			try {
				Schema schema = sf.newSchema(xsdPath);
				u.setSchema(schema);
				u.setEventHandler(new ValidationEventHandler() {
					public boolean handleEvent(ValidationEvent ve) {
						if (ve.getSeverity() == ValidationEvent.WARNING || ve.getSeverity() != ValidationEvent.WARNING) {
							ValidationEventLocator vel = ve.getLocator();
							System.out.println("Line:Col[" + vel.getLineNumber() + ":" + vel.getColumnNumber() + "]:" + ve.getMessage());
							return false;
						}
						return true;
					}
				});
			} catch (org.xml.sax.SAXException se) {
				System.out.println("Unable to validate due to following error.");
				se.printStackTrace();
				throw new RuntimeException(se);
			}
		} catch (JAXBException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
		return u;
	}
}
